import datetime
from decimal import Decimal

from django import forms
from django.db.models import F
from django.conf import settings
from django.db import transaction
from django.contrib import messages
from django_redis import get_redis_connection
from django.shortcuts import render, redirect
from django.core.validators import ValidationError

from web import models
from utils.pager import Pagination
from utils.bootstrap import BootStrapForm
from utils.video import get_old_view_count


def my_order_list(request):
    # 读取之间页面设置的message
    message = messages.get_messages(request)
    for obj in message:
        print(obj.message)

    queryset = models.Order.objects.filter(customer=request.nb_user.id).order_by('-id')
    pager = Pagination(request, queryset)
    context = {'pager': pager}
    return render(request, 'my_order_list.html', context)


class MyOrderModelForm(BootStrapForm, forms.ModelForm):
    class Meta:
        model = models.Order
        fields = ['url', 'count']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        queryset = models.PriceStrategy.objects.all().order_by('count')
        self.price_count_list = []
        text_list = []
        for item in queryset:
            unit_price = item.price / item.count
            text_list.append('>={}:{}元/单'.format(item.count, unit_price))
            self.price_count_list.append([item.count, '>={}:{}元/单'.format(item.count, unit_price), unit_price])

        # 防止价格策略表没内容
        if text_list:
            self.fields['count'].help_text = ', '.join(text_list)
        else:
            self.fields['count'].help_text = '请联系管理员设置价格'

    def clean_count(self):
        count = self.cleaned_data['count']
        min_count_limit = self.price_count_list[0][0]
        if count < min_count_limit:
            raise ValidationError('订单数量不能小于{}'.format(min_count_limit))
        return count


def my_order_list_add(request):
    if request.method == 'GET':
        form = MyOrderModelForm()
        return render(request, 'form.html', {'form': form})

    form = MyOrderModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, 'form.html', {'form': form})

    # 获取到url和数量
    video_url = form.cleaned_data['url']
    video_count = form.cleaned_data['count']
    limit_count, text, unit_price = None, None, None

    # 通过爬虫获原播放量
    status, old_view_count = get_old_view_count(video_url)
    if not status:
        form.add_error('url', '视频原播放量获取失败')
        return render(request, 'form.html', {'form': form})

    # 判断处在那一价格策略
    for idx in range(len(form.price_count_list) - 1, -1, -1):
        limit_count, text, unit_price = form.price_count_list[idx]
        if video_count >= limit_count:
            break
    try:
        with transaction.atomic():
            # 判断用户的级别
            cus_object = models.Customer.objects.filter(id=request.nb_user.id).select_for_update().first()

            # 根据数量获取到价格
            total_price = Decimal(unit_price * video_count)
            real_price = total_price * Decimal(cus_object.level.discount / 100)

            # 检测余额是否足够
            if cus_object.balance < real_price:
                form.add_error('count', '余额不足')
                return render(request, 'form.html', {'form': form})

            # 创建订单生成订单号
            while True:
                ctime = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
                oid = f'{ctime}'
                exists = models.Order.objects.filter(oid=oid).exists()
                if exists:
                    continue
                break

            form.instance.customer_id = request.nb_user.id
            form.instance.oid = oid
            form.instance.price = total_price
            form.instance.real_price = real_price
            form.instance.old_view_count = old_view_count
            form.save()

            # 账户扣款
            # 利用django的F对象，F对象可以直接在数据库中做运算，不用再在python中做运算
            models.Customer.objects.filter(id=request.nb_user.id).update(balance=F('balance') - real_price)

            # 生成交易记录
            models.TransactionHistory.objects.create(
                charge_type=3,
                price=real_price,
                customer_id=request.nb_user.id,
                oid=oid
            )

            # 写入队列 用的是redis
            conn = get_redis_connection('default')
            conn.lpush(settings.QUEUE_TASK_NAME, oid)

    except Exception as e:
        form.add_error('count', '订单创建失败')
        return render(request, 'form.html', {'form': form})

    return redirect('my_order_list')


def my_order_list_cancel(request, pk):
    # 判断订单是否存在或者是否属于当前用户。。.
    order_object = models.Order.objects.filter(
        id=pk,
        active=1,
        status=1,
        customer_id=request.nb_user.id
    ).first()
    if not order_object:
        messages.add_message(request, messages.WARNING, '订单不存在')
        return redirect('my_order_list')
    try:
        with transaction.atomic():
            cus_object = models.Customer.objects.filter(id=request.nb_user.id).select_for_update().first()

            # 变化订单状态 + 事务索防止
            models.Order.objects.filter(id=pk, active=1, status=1, customer=request.nb_user.id).update(status=5)
            # 归还余额
            models.Customer.objects.filter(id=request.nb_user.id).update(balance=F("balance") + order_object.real_price)

            # 在生成交易记录
            models.TransactionHistory.objects.create(
                charge_type=5,
                price=order_object.real_price,
                customer_id=request.nb_user.id,
                oid=order_object.oid
            )
            messages.add_message(request, messages.SUCCESS, '撤单成功')
            return redirect('my_order_list')


    except Exception as e:
        messages.add_message(request, messages.WARNING, f'撤单失败,{e}')
        return redirect('my_order_list')
